import os.path

import pandas as pd

from core.object import BarData, Exchange, Interval, PositionData, AccountData, OrderData, BTTradeData, MessageData
from core.map_const import IntervalMap
import backtrader as bt
from datetime import datetime as datetime_
from core.k_manage import BarGenerator, ArrayManagerBase, BGContainer, AMContainer
from core.constant import *
from tools.framework import get_min_interval, add_sr_to_df

from typing import Callable


class Template:
    def __init__(self):
        # 引擎信息
        self.engine = None
        # K线数据管理
        self.bg_container: BGContainer = BGContainer()
        self.am_container: AMContainer = AMContainer()

        self.last_bar = None
        self.last_node_dc = None

        # 策略模板关键信息
        self.symbol_enum_c = None
        self.symbol_ls = None
        self.interval_ls = None
        self.min_interval = None
        self.am_size = None
        self.am_factor_c: type = None

        # 引擎状态信息
        self.data_flow = False
        self.trade = False

        # 仓位信息
        self.position_dc: dict[str, PositionData] = {}
        # 账户信息
        self.account: AccountData = None
        # 策略运行常用数据
        self.index = 0
        self.size_dc = {}
        self.price_dc = {}
        self.value = 0
        self.qty_dc = {}

    def set_engine(self, engine):
        self.engine = engine

    def update_pos_acc(self, position_dc, account):
        self.position_dc: dict[str, PositionData] = position_dc
        self.account: AccountData = account
        pass

    def load_key_value(self, symbol_enum_c, p_enum_c, am_factor_c: ArrayManagerBase):
        """
        该方法于实际策略中调用，具体位置为继承父类__init__方法后的下一行调用该函数，并传入相关参数。
        :param symbol_enum_c: Symbol Enum的类，可实现字符串类型值到其名字的映射
        :param p_enum_c: 包含参数的枚举类
        :param am_factor_c: 策略所在model对应的ArrayManagerFactor类
        :return:
        """
        self.symbol_enum_c = symbol_enum_c
        self.symbol_ls = [member.value for member in symbol_enum_c]
        self.interval_ls = p_enum_c.intervals.value
        self.min_interval = get_min_interval(self.interval_ls)
        self.am_size = p_enum_c.am_size.value
        self.am_factor_c = am_factor_c

    def start(self):
        self.engine.super_model.master.running_model.canvas_init()
        # 计算合并系数（由于合并导致数据量缩小的倍数）
        min_interval_seconds = IntervalMap[self.min_interval]
        data_interval_seconds = IntervalMap[self.engine.data_server.base_interval]
        merge_coefficient = min_interval_seconds // data_interval_seconds
        # 设置running类的数据长度
        self.engine.super_model.master.running_model.set_data_len(
            int(len(list(self.engine.data_server.ori_data_dc.values())[0]) / merge_coefficient))

        pass

    def get_node_dc(self, node_dc: dict[str, BarData]):
        self.last_node_dc = node_dc
        self.next()

    def get_bar(self, base_bar: BarData):
        self.last_bar = base_bar
        # self.next()  # next接收的并不是bar而是node_dc

    def next(self):
        # -------------------- 1 --------------------------
        for symbol, bar in self.last_node_dc.items():
            is_found = self.bg_container.update(bar)
            if is_found:
                # for interval_o in self.interval_ls:
                #     bg_ins = self.bg_container.get(symbol=symbol, interval=interval_o)
                #     bg_ins.update_bar(bar)
                pass
            else:
                for interval_o in self.interval_ls:
                    am_ins: ArrayManagerBase = self.am_factor_c(size=self.am_size, symbol=symbol, interval=interval_o)
                    bg_ins = BarGenerator(bar.symbol, interval_o, am_ins.update_bar)
                    bg_ins.update_bar(bar)
                    self.bg_container.place(bg_ins)
                    self.am_container.place(am_ins)

        # -------------------- 2 --------------------------
        # 如果最小interval的所有symbol的am均更新完毕，调用on_full
        # pass   # 第一种方案，代码实现
        # 如果当前K线的日内时间总秒数能够整除最小interval总秒数
        # pass   # 第二种方案，未代码实现
        # 遍历最小周期的所有symbol的am
        true_num = 0
        for example_symbol in self.symbol_ls:
            example_am = self.am_container.get(example_symbol, self.min_interval)
            if example_am is None:
                raise ValueError("在am_container已经充分初始化的情况下，仍找不到实例，逻辑错误。")
            else:
                if example_am.datetime == self.last_node_dc[example_symbol].datetime:
                    true_num += 1
                else:
                    pass
            if example_symbol not in self.size_dc.keys():
                self.size_dc[example_symbol] = 0
            if example_symbol not in self.price_dc.keys():
                self.price_dc[example_symbol] = 0
            if example_symbol not in self.qty_dc.keys():
                close_price = self.am_container.get(example_symbol, self.min_interval).close[-1]
                self.qty_dc[example_symbol] = self.account.balance / close_price
        # 检查am是否足够数量且均完成初始化
        am_ideal_num = len(self.symbol_ls) * len(self.interval_ls)
        init_num = 0
        for am in self.am_container.member_ls:
            if am.inited:
                init_num += 1
        if true_num >= len(self.symbol_ls) and init_num >= am_ideal_num:
            # 最小周期am更新，且当前所有am完成初始化
            # -------------------- 3 --------------------------
            # 获取基础账户信息
            # 账户信息
            self.value = self.account.balance + self.account.frozen + self.account.pledge
            if self.position_dc:
                for symbol_o, position_o in self.position_dc.items():
                    self.size_dc[
                        symbol_o] = position_o.volume if position_o.direction == Direction.LONG else -position_o.volume
                    self.price_dc[symbol_o] = position_o.price
                    close_price = self.am_container.get(symbol_o, self.min_interval).close[-1]
                    self.qty_dc[symbol_o] = self.account.balance / close_price
            else:
                for example_symbol in self.symbol_ls:
                    self.size_dc[example_symbol] = 0
                    self.price_dc[example_symbol] = 0
                    close_price = self.am_container.get(example_symbol, self.min_interval).close[-1]
                    self.qty_dc[example_symbol] = self.account.balance / close_price
            self.index += 1
            # 调用策略核心逻辑函数
            self.on_full()
            # 将当前需要在canvas绘制的数据写入canvas_ls
            canvas_data = [self.value, self.am_container.get(self.index_symbol, self.min_interval).close[-1]]
            self.engine.super_model.master.running_model.on_canvas_data(canvas_data)
            # 调用running model的更新canvas方法

    def on_full(self):
        pass

    def stop(self):
        pass

    def notify_order(self, order: OrderData):
        # 订单的成交数量或者订单状态发生变化则推送一次
        pass

    def notify_message(self, message: MessageData):
        # 消息的状态由提交转为未成交则推送一次
        pass

    def notify_position(self, position: PositionData):
        # 仓位的数量发生变化时推送一次
        # 暂未调用
        pass

    def notify_trade(self, order: OrderData):
        # 订单变为完全成交状态时推送一次
        pass

    def notify_cashvalue(self, cash: float, value: float):
        # 每个行情节点推送一次
        pass

    def ddq_print(self, info):
        print(info)
        self.engine.super_model.master.file_manager.log_engine.emit(info, LogName.Running)


class SimulateTemplate(Template):
    def __init__(self):
        super().__init__()

        # action相关回测结果数据
        self.equity_df: pd.DataFrame = None
        self.order_df: pd.DataFrame = None
        self.trade_df: pd.DataFrame = None

    def notify_order(self, order: OrderData):
        if order.status in [Status.ALLTRADED]:
            if order.direction == Direction.LONG:
                direction = Direction.LONG
            else:
                direction = Direction.SHORT

            symbol: str = order.symbol
            exchange: Exchange = order.exchange
            orderid: str = str(order.orderid)

            type: OrderType = order.type
            direction: Direction = direction
            price: float = order.price
            volume: float = order.volume
            traded: float = order.traded
            commission: float = order.commission
            status: Status = Status.ALLTRADED
            datetime: datetime_ = order.datetime

            order_data = OrderData(symbol=symbol, exchange=exchange, orderid=orderid, type=type,
                                   direction=direction, price=price, volume=volume, traded=traded,
                                   commission=commission, status=status, datetime=datetime)
            self.ddq_print(
                f"{direction.value}：标的 {symbol}, 价格 {price}, 数量 {volume}, 类型{type}， 时间{datetime}")

            order_data_sr = order_data.to_sr()
            self.order_df = add_sr_to_df(order_data_sr, self.order_df)

    def notify_trade(self, trade):
        pass

    def notify_cashvalue(self, cash, value):
        self.cash = cash
        self.value = value

        cash_value_dc = {}
        for symbol in self.symbol_ls:
            am = self.am_container.get(symbol, self.min_interval)
            if am is None:
                continue
            datetime = am.datetime
            close: float = am.close[-1]
            cash_value_dc["symbol"] = symbol
            cash_value_dc["close"] = close
            cash_value_dc["cash"] = self.cash
            cash_value_dc["value"] = self.value
            # if symbol.value in self.position_dc.keys():
            #     position: PositionData = self.position_dc[symbol.value]
            #     pnl = position.pnl
            #     if position.volume != 0:
            #         cash_value_dc["symbol"] = symbol.value
            #         cash_value_dc["close"] = close
            #         cash_value_dc["cash"] = cash
            #         cash_value_dc["value"] = position.volume * close
            #         cash_value_dc["size"] = position.volume
            #         cash_value_dc["cost"] = position.price * position.volume
            #         cash_value_dc["pnl"] = pnl
            #         cash_value_dc["price"] = position.price
            #         cash_value_dc["direction"] = position.direction.value
            #     else:
            #         raise ValueError("仓位数量为0，仓位不应存在，逻辑错误。")
            # else:
            #     cash_value_dc["symbol"] = symbol.value
            #     cash_value_dc["close"] = close
            #     cash_value_dc["cash"] = cash
            #     cash_value_dc["value"] = 0.0
            #     cash_value_dc["size"] = 0.0
            #     cash_value_dc["cost"] = 0.0
            #     cash_value_dc["pnl"] = 0.0
            #     cash_value_dc["price"] = 0.0
            #     cash_value_dc["direction"] = Direction.MIDDLE.value

            cash_value_sr = pd.Series(cash_value_dc, dtype=object, name=datetime)
            self.equity_df = add_sr_to_df(cash_value_sr, self.equity_df)

    def start(self):
        super().start()
        pass

    def on_full(self):
        pass

    def stop(self):
        result_folder = self.engine.super_model.result_folder
        result_folder_path = os.path.join(self.engine.super_model.master.file_manager.result_path,
                                          ResultFolder.FHT.value, result_folder)
        # 存储equity_df
        self.engine.super_model.master.file_manager.save_csv(
            self.equity_df, os.path.join(result_folder_path, f"{DataCategory.Equity.value}.csv"))
        # 存储order_df
        self.engine.super_model.master.file_manager.save_csv(
            self.order_df, os.path.join(result_folder_path, f"{DataCategory.Order.value}.csv"))
        # 存储trade_df
        self.engine.super_model.master.file_manager.save_csv(
            self.trade_df, os.path.join(result_folder_path, f"{DataCategory.Trade.value}.csv"))

        print("回测已结束，回测数据已生成。")
        pass

    def buy(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        # 买卖和消息的指令需要传入trader_server来处理
        self.engine.trade_server.buy(symbol, price, volume, type, lifespan_time)
        pass

    def sell(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.sell(symbol, price, volume, type, lifespan_time)
        pass

    def long(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.long(symbol, price, volume, type, lifespan_time)
        pass

    def short(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.short(symbol, price, volume, type, lifespan_time)
        pass


class MessageTemplate(Template):
    def __init__(self):
        super().__init__()
        self.message_df: pd.DataFrame = None
        pass

    def start(self):
        super().start()
        pass

    def on_full(self):
        pass

    def stop(self):
        # 获取message_dc并将其保存至result相应位置
        message_dc = self.engine.trade_server.message_dc
        result_folder = self.engine.super_model.result_folder
        result_folder_path = os.path.join(self.engine.super_model.master.file_manager.result_path,
                                          ResultFolder.FHT.value, result_folder)

        for k, message in message_dc.items():
            sr = message.to_sr()
            self.message_df = add_sr_to_df(sr, self.message_df)
        # 存储message_df
        self.engine.super_model.master.file_manager.save_csv(
            self.message_df, os.path.join(result_folder_path, f"{DataCategory.Message.value}.csv"))

        pass

    def notify_message(self, message: MessageData):
        self.ddq_print(
            f"{message.direction.value}：标的 {message.symbol}, 价格 {message.price}, 级别 {message.level.value}, 内容 {message.content}， 时间{message.datetime}")
        pass

    def buy(self, symbol=None, level=None, content=None, table=None, am=None):
        self.engine.trade_server.buy(symbol, level, content, table, am)
        pass

    def sell(self, symbol=None, level=None, content=None, table=None, am=None):
        self.engine.trade_server.sell(symbol, level, content, table, am)
        pass

    def message(self, symbol=None, level=None, content=None, table=None, am=None):
        self.engine.trade_server.message(symbol, level, content, table, am)
        pass


class RealTemplate(Template):
    def __init__(self):
        super().__init__()

    def start(self):
        pass

    def on_full(self):
        pass

    def stop(self):
        pass

    def buy(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.buy(symbol, price, volume, type, lifespan_time)
        pass

    def sell(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.sell(symbol, price, volume, type, lifespan_time)
        pass

    def long(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.long(symbol, price, volume, type, lifespan_time)
        pass

    def short(self, symbol=None, price=None, volume=None, type=None, lifespan_time=None):
        self.engine.trade_server.short(symbol, price, volume, type, lifespan_time)
        pass


class BacktestingTemplate(bt.Strategy):
    def __init__(self, p_dc=None):
        # K线数据管理
        self.bg_container: BGContainer = BGContainer()
        self.am_container: AMContainer = AMContainer()

        self.index_symbol = ''
        self.gen_file = True
        self.symbol_ls = None
        self.interval_ls = None
        self.min_interval = None
        self.am_size = None
        self.am_factor_c: Callable = None
        self.super_model = None

        # 仓位信息

        # 仓位信息
        self.position_dc: dict[str, PositionData] = {}
        # 账户信息
        self.account: AccountData = None
        # 策略运行常用数据
        self.index = 0

        self.size_dc = {}
        self.price_dc = {}
        self.value = 0
        self.cash = 0
        self.qty_dc = {}

        # action相关回测结果数据
        self.equity_df: pd.DataFrame = None
        self.order_df: pd.DataFrame = None
        self.trade_df: pd.DataFrame = None
        # 相应列表容器
        self.equity_df_cont = []
        self.order_df_cont = []
        self.trade_df_cont = []
        # 参数信息
        self.p_dc = p_dc
        pass

    def notify_order(self, order):
        if order.status in [order.Rejected, order.Margin]:
            info = f"订单被拒或保证金不足，注意检查。价格：{order.price}，数量：{order.size}。"
            self.ddq_print(info)

        if order.status in [order.Completed]:
            if order.size > 0:
                direction = Direction.LONG
            else:
                direction = Direction.SHORT

            symbol: str = order.data._name
            exchange: Exchange = Exchange.DDQ
            orderid: str = str(order.ref)

            type: OrderType = OrderType.LIMIT if order.ordtype == bt.Order.Limit else OrderType.MARKET
            direction: Direction = direction
            price: float = order.executed.price
            volume: float = order.size
            traded: float = order.executed.size
            commission: float = order.executed.comm
            status: Status = Status.ALLTRADED
            datetime: datetime_ = bt.num2date(order.created.dt)

            order_data = OrderData(symbol=symbol, exchange=exchange, orderid=orderid, type=type,
                                   direction=direction, price=price, volume=volume, traded=traded,
                                   commission=commission, status=status, datetime=datetime)
            if self.gen_file:
                order_data_sr = order_data.to_sr()
                self.order_df = add_sr_to_df(order_data_sr, self.order_df)
                if len(self.order_df) > 10000:
                    self.order_df_cont.append(self.order_df)
                    self.order_df: pd.DataFrame = None

            info = f"{order_data.direction.value}：标的 {order_data.symbol}, 价格 {order_data.price}, 数量 {order_data.volume}, 时间 {order_data.datetime}"
            self.ddq_print(info)

        pass

    def notify_trade(self, trade):
        if self.gen_file:
            if trade.isclosed:
                symbol: str = trade.data._name
                exchange: Exchange = Exchange.DDQ

                commission: float = trade.commission
                pnl: float = trade.pnl
                is_closed: bool = trade.isclosed
                dt_open: datetime_ = bt.num2date(trade.dtopen)
                dt_close: datetime_ = bt.num2date(trade.dtclose)

                trade_data = BTTradeData(symbol=symbol, exchange=exchange, commission=commission,
                                         pnl=pnl, is_closed=is_closed, dt_open=dt_open, dt_close=dt_close)
                trade_data_sr = trade_data.to_sr()
                self.trade_df = add_sr_to_df(trade_data_sr, self.trade_df)
                if len(self.trade_df) > 10000:
                    self.trade_df_cont.append(self.trade_df)
                    self.trade_df: pd.DataFrame = None

    def notify_cashvalue(self, cash, value):
        self.cash = cash
        self.value = value
        if self.gen_file:
            cash_value_dc = {}

            data = self.getdatabyname(self.index_symbol)
            datetime: datetime_ = bt.num2date(data.datetime[0])
            close: float = data.close[0]
            cash_value_dc["symbol"] = self.index_symbol
            cash_value_dc["close"] = close
            cash_value_dc["cash"] = self.cash
            cash_value_dc["value"] = self.value
            cash_value_sr = pd.Series(cash_value_dc, dtype=object, name=datetime)
            self.equity_df = add_sr_to_df(cash_value_sr, self.equity_df)
            if len(self.equity_df) > 10000:
                self.equity_df_cont.append(self.equity_df)
                self.equity_df: pd.DataFrame = None
        # for symbol in self.symbol_ls:
        #     data = self.getdatabyname(symbol)
        #     datetime: datetime_ = bt.num2date(data.datetime[0])
        #     close: float = data.close[0]
        #     position = self.getposition(data)
        #     rise_point = close - position.price
        #     pnl = rise_point * position.size if position.size > 0 else -rise_point * position.size
        #     if position.size != 0:
        #         cash_value_dc["symbol"] = symbol
        #         cash_value_dc["close"] = close
        #         cash_value_dc["cash"] = cash
        #         cash_value_dc["value"] = abs(position.size * close)
        #         cash_value_dc["size"] = position.size
        #         cash_value_dc["cost"] = position.price * abs(position.size)
        #         cash_value_dc["pnl"] = pnl
        #         cash_value_dc["price"] = position.price
        #         cash_value_dc["direction"] = Direction.LONG.value if position.size > 0 else (
        #             Direction.SHORT.value if position.size < 0 else
        #             Direction.MIDDLE.value)
        #     else:
        #         pass

        pass

    def start(self):
        # backtrader引擎内为symbol_ls、interval_ls、min_interval、am_size和am_factor_c等参数赋值
        try:
            self.gen_file = eval(self.p_dc["gen_file"])
        except:
            self.gen_file = False
        self.symbol_ls = self.p_dc["symbols"]
        if '指数' in self.symbol_ls:
            self.index_symbol = '指数'
        else:
            self.index_symbol = self.symbol_ls[0]
        self.interval_ls = self.p_dc["intervals"]
        self.min_interval = get_min_interval(self.interval_ls)
        self.am_size = self.p_dc["am_size"]
        self.am_factor_c = self.p_dc["am_factor_c"]
        self.super_model = self.p_dc["super_model"]
        # 清空running的canvas
        self.super_model.master.running_model.canvas_init()
        # 设置running类的数据长度
        data = self.getdatabyname(self.index_symbol)
        self.super_model.master.running_model.set_data_len(len(data.array))

        pass

    def next(self):
        now_datetime = None
        for symbol in self.symbol_ls:
            data = self.getdatabyname(symbol)
            exchange: Exchange = Exchange.DDQ
            datetime: datetime_ = bt.num2date(data.datetime[0])
            now_datetime = datetime
            interval: Interval = self.p_dc["interval"]
            volume: float = data.volume[0]
            turnover: float = 0
            open_interest: float = 0
            open_price: float = data.open[0]
            high_price: float = data.high[0]
            low_price: float = data.low[0]
            close_price: float = data.close[0]

            bar: BarData = BarData(symbol, exchange, datetime, interval, volume, turnover, open_interest, open_price,
                                   high_price, low_price, close_price)
            is_found = self.bg_container.update(bar)
            if is_found:
                pass
            else:
                for interval_o in self.interval_ls:
                    am_ins: ArrayManagerBase = self.am_factor_c(size=self.am_size, symbol=symbol, interval=interval_o)
                    bg_ins = BarGenerator(bar.symbol, interval_o, am_ins.update_bar)
                    bg_ins.update_bar(bar)
                    self.bg_container.place(bg_ins)
                    self.am_container.place(am_ins)
        # -------------------- 2 --------------------------
        # 如果最小interval的所有symbol的am均更新完毕，调用on_full
        # pass   # 第一种方案，代码实现
        # 如果当前K线的日内时间总秒数能够整除最小interval总秒数
        # pass   # 第二种方案，未代码实现
        # 遍历最小周期的所有symbol的am
        true_num = 0
        for example_symbol in self.symbol_ls:
            example_am = self.am_container.get(example_symbol, self.min_interval)
            if example_am is None:
                pass
            else:
                if example_am.datetime == now_datetime:
                    true_num += 1
                else:
                    pass
        # 检查am是否足够数量且均完成初始化
        am_ideal_num = len(self.symbol_ls) * len(self.interval_ls)
        init_num = 0
        for am in self.am_container.member_ls:
            if am.inited:
                init_num += 1

        if true_num >= len(self.symbol_ls) and init_num >= am_ideal_num:
            # 最小周期am更新，且当前所有am完成初始化
            # -------------------- 3 --------------------------
            # 获取基础账户信息
            # 账户信息
            self.account = AccountData(account_id="bt", balance=self.cash, frozen=self.value - self.cash)
            self.position_dc: [str, PositionData] = {}
            for symbol in self.symbol_ls:
                data = self.getdatabyname(symbol)
                close = data.close[0]
                position = self.getposition(data)
                if position.price != 0:
                    rise_point = close - position.price
                    self.position_dc[symbol] = PositionData(
                        symbol=symbol,
                        exchange=Exchange.DDQ,
                        direction=Direction.LONG if position.size > 0 else Direction.SHORT if position.size == 0 else Direction.MIDDLE,
                        volume=abs(position.size),
                        frozen=0,
                        price=position.price,
                        pnl=rise_point * position.size if position.size > 0 else -rise_point * position.size
                    )
                else:
                    pass

            self.size_dc = {}
            self.price_dc = {}
            self.qty_dc = {}

            for symbol_o, position_o in self.position_dc.items():
                self.size_dc[
                    symbol_o] = position_o.volume if position_o.direction == Direction.LONG else -position_o.volume
                self.price_dc[symbol_o] = position_o.price
                close_price = self.am_container.get(symbol_o, self.min_interval).close[-1]
                self.qty_dc[symbol_o] = self.account.balance / close_price
            # 若未进行赋值则填充默认值
            for symbol_o in self.symbol_ls:
                if symbol_o not in self.size_dc.keys():
                    self.size_dc[symbol_o] = 0
                if symbol_o not in self.price_dc.keys():
                    self.price_dc[symbol_o] = 0
                if symbol_o not in self.qty_dc.keys():
                    close_price = self.am_container.get(symbol_o, self.min_interval).close[-1]
                    self.qty_dc[symbol_o] = self.account.balance / close_price
            # 更新K线索引，与提供的周期中最小周期保持一致。
            self.index += 1
            # 调用策略核心逻辑函数
            self.on_full()
            # 将当前的需要参与绘制动画的数据加入canvas_ls
            # 包含两个元素的列表，包含一个净值和一个收盘价
            self.value = self.broker.getvalue()
            data = self.getdatabyname(self.index_symbol)
            canvas_data = [self.value, data.close[0]]
            self.super_model.master.running_model.on_canvas_data(canvas_data)
            # 调用running model的更新canvas方法

        pass

    def on_full(self):

        pass

    def stop(self):
        if self.gen_file:
            result_folder_path = self.p_dc["result_folder_path"]
            # self.equity_df.index.name = "datetime"
            # self.order_df.index.name = "datetime"
            # self.trade_df.index.name = "datetime"
            # 组合列表及相应的最新元素
            self.order_df_cont.append(self.order_df)
            self.trade_df_cont.append(self.trade_df)
            self.equity_df_cont.append(self.equity_df)

            self.order_df = pd.concat(self.order_df_cont, axis=0)
            self.trade_df = pd.concat(self.trade_df_cont, axis=0)
            self.equity_df = pd.concat(self.equity_df_cont, axis=0)

            # 存储equity_df
            self.super_model.master.file_manager.save_csv(self.equity_df, os.path.join(result_folder_path,
                                                                                       f"{DataCategory.Equity.value}.csv"))
            # 存储order_df
            self.super_model.master.file_manager.save_csv(self.order_df, os.path.join(result_folder_path,
                                                                                      f"{DataCategory.Order.value}.csv"))
            # 存储trade_df
            self.super_model.master.file_manager.save_csv(self.trade_df, os.path.join(result_folder_path,
                                                                                      f"{DataCategory.Trade.value}.csv"))

            print("回测已结束，回测数据已生成。")
        else:
            print("回测已结束，未保存回测数据。")
        pass

    def buy(self, symbol=None,
            size=None, price=None, plimit=None,
            exectype=None, valid=None, tradeid=0, oco=None,
            trailamount=None, trailpercent=None,
            parent=None, transmit=True,
            **kwargs):
        if isinstance(symbol, str):
            data = self.getdatabyname(symbol)
            return super().buy(data=data,
                               size=size, price=price, plimit=plimit,
                               exectype=exectype, valid=valid, tradeid=tradeid, oco=oco,
                               trailamount=trailamount, trailpercent=trailpercent,
                               parent=parent, transmit=transmit,
                               **kwargs)
        elif symbol is None:
            return super().buy(size=size, price=price, plimit=plimit,
                               exectype=exectype, valid=valid, tradeid=tradeid, oco=oco,
                               trailamount=trailamount, trailpercent=trailpercent,
                               parent=parent, transmit=transmit,
                               **kwargs)
        else:
            raise ValueError("symbol参数不可为空，且必须为字符串格式。")

    def sell(self, symbol=None,
             size=None, price=None, plimit=None,
             exectype=None, valid=None, tradeid=0, oco=None,
             trailamount=None, trailpercent=None,
             parent=None, transmit=True,
             **kwargs):
        if isinstance(symbol, str):
            data = self.getdatabyname(symbol)
            return super().sell(data=data,
                                size=size, price=price, plimit=plimit,
                                exectype=exectype, valid=valid, tradeid=tradeid, oco=oco,
                                trailamount=trailamount, trailpercent=trailpercent,
                                parent=parent, transmit=transmit,
                                **kwargs)
        elif symbol is None:
            return super().sell(size=size, price=price, plimit=plimit,
                                exectype=exectype, valid=valid, tradeid=tradeid, oco=oco,
                                trailamount=trailamount, trailpercent=trailpercent,
                                parent=parent, transmit=transmit,
                                **kwargs)
        else:
            raise ValueError("symbol参数不可为空，且必须为字符串格式。")
        # support = self.data_map[symbol]
        # print(f"symbol={symbol}, size={size}, price={price}")

    def close(self, symbol=None, size=None, **kwargs):
        if isinstance(symbol, str):
            data = self.getdatabyname(symbol)
            return super().close(data=data, size=size, **kwargs)
        elif symbol is None:
            return super().close(size=size, **kwargs)
        else:
            raise ValueError("symbol参数不可为空，且必须为字符串格式。")
        # support = self.data_map[symbol]
        # print(f"symbol={symbol}, size={size}")

    def ddq_print(self, info):
        print(info)
        self.super_model.master.file_manager.log_engine.emit(info, LogName.Running)
